package com.ces.chain;
/*
 * @Author wuchengcheng
 * @Date 2019-10-13 11:19
 */

import com.ces.chain.annon.Intercepts;
import com.ces.chain.annon.Signature;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Chain implements InvocationHandler {

    private final Interceptor interceptor;
    private final Map<Class<?>, Set<Method>> signature;
    private final Object target;


    private Chain(Object target,Interceptor interceptor,Map<Class<?>, Set<Method>> signature){
        this.target=target;//代理中的目标对象
        this.signature=signature;//代理对象的签名
        this.interceptor=interceptor;//代理的拦截器
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        try {
            //获取目标对象接口方法列表
            Set<Method> methods = signature.get(method.getDeclaringClass());
            if(methods!=null&&methods.contains(method)){
                return interceptor.intercept(new Invocation(target, method, args));
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //若代理不存在则直接执行
            return method.invoke(target,args);
    }

    // 真正执行代理的方法，此处使用的是JDK代理，所以目标对象必须是基于接口的
    public static Object wrap(Object target, Interceptor interceptor) {
        Map<Class<?>, Set<Method>> signatures = getSignatureMap(interceptor);
        Class<?> type = target.getClass();
        Class<?>[] interfaces = getAllInterfaces(type, signatures);
        if (interfaces.length > 0) {
            return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Chain(target, interceptor, signatures));
        }
        return target;
    }

// 真正执行代理的方法，此处使用的是JDK代理，所以目标对象必须是基于接口的
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
    Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
    if (interceptsAnnotation == null) {
        throw new RuntimeException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
    }
    Signature[] sigs = interceptsAnnotation.value();
    Map<Class<?>, Set<Method>> signatures = new HashMap<>();
    for (Signature sig : sigs) {
        Set<Method> methods = signatures.computeIfAbsent(sig.type(), k -> new HashSet<>());
        try {
            Method method = sig.type().getMethod(sig.method(), sig.args());
            methods.add(method);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
        }
    }
    return signatures;
}
    // 根据代理对象的签名，获取目标对象的接口（因为使用JDK代理，因此所有代理行为都是基于接口的）
    private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatures) {
        Set<Class<?>> interfaces = new HashSet<>();
        while (type != null) {
            for (Class<?> c : type.getInterfaces()) {
                if (signatures.containsKey(c)) {
                    interfaces.add(c);
                }
            }
            type = type.getSuperclass();
        }
        return interfaces.toArray(new Class<?>[interfaces.size()]);
    }


}
